package framework

import (
	config "Hypnos-Soundcore/components/config"
	"Hypnos-Soundcore/components/crontab"
	"Hypnos-Soundcore/components/helper"
	"Hypnos-Soundcore/components/nacos"
	"Hypnos-Soundcore/components/trafficcontrol"
	"Hypnos-Soundcore/constants"
	"Hypnos-Soundcore/middleware/cors"
	"Hypnos-Soundcore/middleware/recovery"
	"Hypnos-Soundcore/middleware/stats"
	"flag"
	"fmt"
	"github.com/DeanThompson/ginpprof"
	"github.com/gin-gonic/gin"
	"golang.org/x/sync/errgroup"
	"gopkg.in/yaml.v2"
	"time"
)

// ControllerFunc init controllers
type ControllerFunc func(*gin.Engine)

var xconf *config.XConfig
var g errgroup.Group

const (
	NacosGroupID            = "Hypnos-Soundcore"
	NacosDataIDServiceBasic = "service_basic"
)

var nacosNameSpace = flag.String("nacos-ns", "Security-CI", "nacos name space")
var nacosIP = flag.String("nacos-ip", "10.1.54.115", "nacos ip")
var nacosPort = flag.Int("nacos-port", 8848, "nacos port")
var nacosUserName = flag.String("nacos-username", "nacos", "nacos user name")
var nacosPassWord = flag.String("nacos-password", "nacos", "nacos password")

// MainEntry common main entry
func MainEntry(controllerFunc ControllerFunc) {
	flag.Parse()
	// init config
	sc := []nacos.ServerConfig{
		{
			IpAddr:      *nacosIP,
			Port:        uint64(*nacosPort),
			Scheme:      "http",
			ContextPath: "/nacos",
		},
	}

	client, err := nacos.NewIConfigClient(
		nacos.WithNamespaceID(*nacosNameSpace),
		nacos.WithTimeout(5000),
		nacos.WithLogLevel("debug"),
		nacos.WithNotLoadCacheAtStart(true),
		nacos.WithCacheDir("./logs/"),
		nacos.WithLogDir("./logs/"),
		nacos.WithRotateTime("1h"),
		nacos.WithUsername(*nacosUserName),
		nacos.WithPassword(*nacosPassWord),
		nacos.WithServerConfig(sc))

	if err != nil {
		fmt.Printf("newConfigClient error:%v", err)
		return
	}
	// 使用全局配置中心
	nacos.InitDefaultNacosConfigSource(client, nacos.WithGroup(NacosGroupID), nacos.WithDataID(NacosDataIDServiceBasic))
	kv, err := nacos.GetDefaultNacosConfigSource().Load()
	if err != nil {
		fmt.Printf("configSource load error:%v", err)
		return
	}
	// load global config and validating config data
	xconf = config.GetXConfig()
	for _, v := range kv {
		if v.Key == NacosDataIDServiceBasic {
			err = yaml.Unmarshal(v.Value, xconf)
			if err != nil {
				fmt.Printf("yaml.Unmarshal error:%v", err)
				return
			}
		}
	}

	if err != nil {
		fmt.Printf("configSource load error:%v", err)
		return
	}
	xconf.TrafficControl = trafficcontrol.NacosConfig{
		NacosServerConfig: trafficcontrol.NacosServerConfig{
			IpAddr: *nacosIP,
			Port:   uint64(*nacosPort),
		},
		NacosClientConfig: trafficcontrol.NacosClientConfig{
			NamespaceId:         *nacosNameSpace,
			TimeoutMs:           5000,
			NotLoadCacheAtStart: true,
			LogDir:              "./logs/",
			CacheDir:            "./logs/",
			RotateTime:          "1h",
			// MaxAge              int64
			LogLevel: "debug",
			Username: *nacosUserName,
			Password: *nacosPassWord,
		},
		DataId: NacosDataIDServiceBasic,
		Group:  constants.NacosTrafficControlGroupID,
	}
	trafficcontrol.StartTrafficControl(xconf.TrafficControl)

	// 设置环境参数
	constants.SetEnv(xconf.Env)

	// init crontab
	crontab.InitCrontab()
	defer crontab.ReleaseCrontab()

	defer helper.WarningActionPrintln(constants.TagFramework, constants.ActionServiveExited,
		"", "", 0)

	// init mysql
	dbErr := helper.InitMysql(xconf)
	if dbErr != nil {
		helper.WarningActionPrintln(constants.TagFramework, constants.ActionServiveExited,
			"", dbErr.Error(), 0)
		return
	}

	defer helper.UninitMysql()

	// 定时清除日志文件
	helper.DoCronLogClear(xconf)

	helper.WarningActionPrintln(constants.TagFramework, constants.ActionServiveStarted,
		"", "", 0)
	// start listen and serving
	gin.SetMode(xconf.Gin.Mode)
	engine := gin.New()
	engine.Use(recovery.Recovery())
	engine.Use(cors.Cors(cors.Config{
		Origins: "*",
		Methods: "GET, PUT, POST, DELETE",
		//RequestHeaders:  "Origin, Authorization, Content-Type, " + auth.AuthUser + ", " + auth.AuthToken,
		ExposedHeaders:  "",
		MaxAge:          1 * time.Minute,
		Credentials:     true,
		ValidateHeaders: false,
	}))
	// stats修改为实现将用户操作写日志文件的功能
	engine.Use(stats.Stats())
	if xconf.Gin.Pprof {
		ginpprof.Wrap(engine)
	}

	if controllerFunc != nil {
		controllerFunc(engine)
	}
	// https or http transfering
	helper.WarningActionPrintln(constants.TagFramework, constants.ActionServiceListenAndServe,
		"", fmt.Sprintf("Listen and serve at %s", xconf.Network.ListenPort), 0)
	if serveErr := ListenAndServe(xconf, engine); serveErr != nil {
		helper.WarningActionPrintln(constants.TagFramework,
			constants.ActionServiceListenAndServe, "", serveErr.Error(), 0)
	}
}
